package com.guoke.weather.fengyun4a;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;



/**
 * 下载风云4号卫星云图的工具类
 * 
 * @author Ma Chao
 * @version 2020年8月6日 下午4:15:47
 */
public final class Fengyun4aUtil {
    Fengyun4aUtil() {}

    private static final String BASE_URL =
            "http://rsapp.nsmc.org.cn/swapQuery/public/tileServer/getTile/fy-4a/full_disk/NatureColor/{}/jpg/4/";
    private static final String DETAIL_URL = "{}/{}.png";

    private static final String[] PIC_TIMES = new String[] {"0000", "0015", "0100", "0200", "0245",
            "0300", "0315", "0400", "0500", "0545", "0600", "0615", "0700", "0800", "0845", "0900",
            "0915", "1000", "1100", "1145", "1200", "1215", "1300", "1400", "1445", "1500", "1515",
            "1600", "1700", "1745", "1800", "1815", "1900", "2000", "2045", "2100", "2115", "2200",
            "2300", "2345"};

    private static final String BASE_DIR = "D:\\Fengyun4a";
    private static final String PIC_FILE_TYPE = ".jpg";

    public static void batchDownload(String date, String time) {
        validParam(date, time);
        String datetime = new StringBuilder(date).append(time).append("00").toString();
        String baseUrl = StrUtil.format(BASE_URL, datetime);
        for (int x = 0; x <= 15; x++) {
            for (int y = 0; y <= 15;) {
                String detailUrl = StrUtil.format(DETAIL_URL, x, y);
                String url = new StringBuilder(baseUrl).append(detailUrl).toString();
                if (download(url, date, time, x, y)) {
                    y++;
                }
            }
        }
    }

    public static void merge(String date, String time) throws IOException {
        mergeX(date, time);
        mergeY(date, time);
        removeX(date, time);
    }

    public static void mergeX(String date, String time) throws IOException {
        String dir = getFileDir(date, time);
        // 先横向拼接
        List<BufferedImage> xImgs = null;
        for (int x = 0; x <= 15; x++) {
            xImgs = new ArrayList<>();
            for (int y = 0; y <= 15; y++) {
                String imgUrl = dir + File.separator + "4-" + x + "-" + y + PIC_FILE_TYPE;
                xImgs.add(ImageIO.read(new File(imgUrl)));
            }
            BufferedImage img = mergeImage(xImgs.get(0), xImgs.get(1), true);
            for (int i = 2; i <= 15; i++) {
                img = mergeImage(img, xImgs.get(i), true);
            }
            generateSaveFile(img, dir + File.separator + x + PIC_FILE_TYPE);
            img.flush();
            xImgs = null;
        }
    }

    public static void mergeY(String date, String time) throws IOException {
        String dir = getFileDir(date, time);
        // 再纵向拼接
        BufferedImage yImg =
                mergeImage(ImageIO.read(new File(dir + File.separator + "0" + PIC_FILE_TYPE)),
                        ImageIO.read(new File(dir + File.separator + "1" + PIC_FILE_TYPE)), false);
        for (int i = 2; i <= 15; i++) {
            yImg = mergeImage(yImg,
                    ImageIO.read(new File(dir + File.separator + i + PIC_FILE_TYPE)), false);
        }
        generateSaveFile(yImg, dir + File.separator + date + "-" + time + PIC_FILE_TYPE);
        yImg.flush();
    }

    public static void removeX(String date, String time) throws IOException {
        String dir = getFileDir(date, time);
        for (int i = 0; i <= 15; i++) {
            File file = new File(dir + File.separator + i + PIC_FILE_TYPE);
            if (file.exists() && file.isFile()) {
                file.delete();
            }
        }
    }

    private static void validParam(String dateString, String time) {
        Date date = DateUtil.parse(dateString, "yyyyMMDD");
        
        if (null == date) {
            throw new ValidateException("日期" + dateString + "不是yyyyMMdd格式！");
        }
        List<String> times = Arrays.asList(PIC_TIMES);
        if (!times.contains(time)) {
            throw new ValidateException("风云4A卫星没有提供" + time + "时间的云图！");
        }
    }

    private static boolean download(String url, String date, String time, int x, int y) {
        HttpURLConnection conn = null;
        InputStream inputStream = null;
        BufferedInputStream bis = null;

        File dir = new File(getFileDir(date, time));
        if (!dir.isDirectory() && !dir.exists()) {
            dir.mkdirs();
        }
        String fileName = new StringBuilder().append("4-").append(x).append("-").append(y)
                .append(PIC_FILE_TYPE).toString();
        try (FileOutputStream out = new FileOutputStream(dir + File.separator + fileName);) {
            // 建立链接
            URL httpUrl = new URL(url);
            conn = (HttpURLConnection) httpUrl.openConnection();
            // 以Post方式提交表单，默认get方式
            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            // post方式不能使用缓存
            conn.setUseCaches(false);
            // 连接指定的资源
            conn.connect();
            // 获取网络输入流
            inputStream = conn.getInputStream();
            bis = new BufferedInputStream(inputStream);
            byte b[] = new byte[1024];
            int len = 0;
            while ((len = bis.read(b)) != -1) {
                out.write(b, 0, len);
            }
            File file = new File(dir + File.separator + fileName);
            if (file.exists() && file.length() == 0) {
                return false;
            }
            System.out.println(fileName + "下载完成.");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private static String getFileDir(String date, String time) {
        return BASE_DIR + File.separator + date + File.separator + time;
    }

    private static void generateSaveFile(BufferedImage buffImg, String savePath)
            throws IOException {
        int temp = savePath.lastIndexOf('.') + 1;
        File outFile = new File(savePath);
        if (!outFile.exists()) {
            outFile.createNewFile();
        }
        ImageIO.write(buffImg, savePath.substring(temp), outFile);
        System.out.println("图像" + savePath + "保存成功");
    }

    /**
     * 
     * @param img1
     * @param img2
     * @param isHorizontal 为true时表示水平方向合并，为false时表示垂直方向合并
     * @return
     */
    private static BufferedImage mergeImage(BufferedImage img1, BufferedImage img2,
            boolean isHorizontal) {
        int w1 = img1.getWidth();
        int h1 = img1.getHeight();
        int w2 = img2.getWidth();
        int h2 = img2.getHeight();

        // 从图片中读取RGB
        int[] imageArrayOne = new int[w1 * h1];
        imageArrayOne = img1.getRGB(0, 0, w1, h1, imageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
        int[] imageArrayTwo = new int[w2 * h2];
        imageArrayTwo = img2.getRGB(0, 0, w2, h2, imageArrayTwo, 0, w2);

        // 生成新图片
        BufferedImage destImage = null;
        if (isHorizontal) { // 水平方向合并
            destImage = new BufferedImage(w1 + w2, h1, BufferedImage.TYPE_INT_RGB);
            destImage.setRGB(0, 0, w1, h1, imageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            destImage.setRGB(w1, 0, w2, h2, imageArrayTwo, 0, w2);
        } else { // 垂直方向合并
            destImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB);
            destImage.setRGB(0, 0, w1, h1, imageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            destImage.setRGB(0, h1, w2, h2, imageArrayTwo, 0, w2); // 设置下半部分的RGB
        }
        return destImage;
    }
}
